package org.broadinstitute.hellbender.tools.copynumber.formats.collections;

import org.broadinstitute.hellbender.exceptions.UserException;
import org.broadinstitute.hellbender.tools.copynumber.GermlineCNVCaller;
import org.broadinstitute.hellbender.tools.copynumber.PostprocessGermlineCNVCalls;
import org.broadinstitute.hellbender.tools.copynumber.formats.metadata.SampleLocatableMetadata;
import org.broadinstitute.hellbender.tools.copynumber.formats.records.LinearCopyRatio;
import org.broadinstitute.hellbender.utils.SimpleInterval;
import org.broadinstitute.hellbender.utils.tsv.DataLine;
import org.broadinstitute.hellbender.utils.tsv.TableColumnCollection;

import java.io.File;
import java.util.List;
import java.util.function.BiConsumer;
import java.util.function.Function;

/**
 * Collection of copy ratios in linear space generated by {@link GermlineCNVCaller} with their corresponding intervals
 *
 * @author Andrey Smirnov &lt;asmirnov@broadinstitute.org&gt;
 */
public class LinearCopyRatioCollection extends AbstractSampleLocatableCollection<LinearCopyRatio> {

    enum DenoisedLocatableCopyRatioTableColumn {
        CONTIG,
        START,
        END,
        LINEAR_COPY_RATIO;

        static final TableColumnCollection COLUMNS = new TableColumnCollection((Object[]) values());
    }

    public LinearCopyRatioCollection(final File inputFile) {
        super(inputFile, DenoisedLocatableCopyRatioTableColumn.COLUMNS,
                getLinearCopyRatioRecordFromDataLineDecoder(),
                getLinearCopyRatioRecordToDataLineEncoder());
    }

    public LinearCopyRatioCollection(final SampleLocatableMetadata metadata,
                                     final List<LinearCopyRatio> linearCopyRatioList) {
        super(metadata, linearCopyRatioList, DenoisedLocatableCopyRatioTableColumn.COLUMNS,
                getLinearCopyRatioRecordFromDataLineDecoder(),
                getLinearCopyRatioRecordToDataLineEncoder());
    }

    /**
     * Generates an instance of {@link LinearCopyRatio} from a {@link DataLine} entry read from a denoised copy
     * ratio file output by {@link PostprocessGermlineCNVCalls}
     */
    private static Function<DataLine, LinearCopyRatio> getLinearCopyRatioRecordFromDataLineDecoder() {
        return dataLine -> {
            try {
                final String contig = dataLine.get(DenoisedLocatableCopyRatioTableColumn.CONTIG);
                final int start = dataLine.getInt(DenoisedLocatableCopyRatioTableColumn.START);
                final int end = dataLine.getInt(DenoisedLocatableCopyRatioTableColumn.END);
                final double denoisedCopyRatio = dataLine.getDouble(DenoisedLocatableCopyRatioTableColumn.LINEAR_COPY_RATIO);
                return new LinearCopyRatio(new SimpleInterval(contig, start, end), denoisedCopyRatio);
            } catch (final IllegalArgumentException ex) {
                throw new UserException.BadInput(String.format("Validation error occurred on line %d of the denoised copy ratio file : ", dataLine.getLineNumber())
                        + ex.getMessage());
            }
        };
    }

    /**
     * Generates an instance of {@link DataLine} from {@link LinearCopyRatio}
     */
    private static BiConsumer<LinearCopyRatio, DataLine> getLinearCopyRatioRecordToDataLineEncoder() {
        return (linearCopyRatio, dataLine) -> dataLine.append(linearCopyRatio.getContig())
                .append(linearCopyRatio.getStart())
                .append(linearCopyRatio.getEnd())
                .append(linearCopyRatio.getLinearCopyRatio());
    }

}
